﻿using System;

namespace MathExpression
{
    internal class Scalar : IMathExpression
    {
        private readonly double _value;

        public Scalar(double value)
        {
            _value = value;
        }

        public IExpressionData Data
        {
            get { return new ScalarData(_value); }
        }

        public IMathExpression Reverse()
        {
            if (Math.Abs(_value - 0.0) < double.Epsilon)
            {
                throw new DivideByZeroException("Деление на ноль невозможно");
            }
            return new Scalar(1.0/_value);
        }

        public IMathExpression Add(IMathExpression expression)
        {
            if (expression is Scalar)
            {
                return Add(expression as Scalar);
            }
            if (expression is Polynomial)
            {
                return Add(expression as Polynomial);
            }
            return null;
        }

        public IMathExpression Subtract(IMathExpression expression)
        {
            if (expression is Scalar)
            {
                return Subtract(expression as Scalar);
            }
            if (expression is Polynomial)
            {
                return Subtract(expression as Polynomial);
            }
            return null;
        }

        public IMathExpression Multiply(IMathExpression expression)
        {
            if (expression is Scalar)
            {
                return Multiply(expression as Scalar);
            }
            if (expression is Polynomial)
            {
                return Multiply(expression as Polynomial);
            }
            return null;
        }

        public IMathExpression Divide(IMathExpression expression)
        {
            IMathExpression denominator = expression.Reverse();
            return Multiply(denominator);
        }

        private IMathExpression Add(Scalar x)
        {
            return new Scalar(_value + x._value);
        }

        private IMathExpression Add(Polynomial polynomial)
        {
            return polynomial.Add(this);
        }

        private IMathExpression Subtract(Scalar x)
        {
            return new Scalar(_value - x._value);
        }

        private IMathExpression Subtract(Polynomial polynomial)
        {
            IMathExpression expression = polynomial.Subtract(this);
            var minus = new Scalar(-1.0);
            return expression.Multiply(minus);
        }

        private IMathExpression Multiply(Scalar x)
        {
            return new Scalar(_value*x._value);
        }

        private IMathExpression Multiply(Polynomial polynomial)
        {
            return polynomial.Multiply(this);
        }

        public IMathExpression Clone()
        {
            return new Scalar(_value);
        }

        public override bool Equals(object obj)
        {
            var scalar = obj as Scalar;
            if (scalar == null)
            {
                return false;
            }
            return Math.Abs(scalar._value - _value) < double.Epsilon;
        }

        public bool Equals(Scalar other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return other._value.Equals(_value);
        }

        public override int GetHashCode()
        {
            return _value.GetHashCode();
        }
    }
}